package com.bitcarton.disso.core.filter;

import com.bitcarton.disso.core.annotation.Handler;
import com.bitcarton.disso.core.annotation.Login;
import com.bitcarton.disso.core.config.Config;
import com.bitcarton.disso.core.helper.SsoLoginHelper;
import com.bitcarton.disso.core.utils.CookieUtil;
import com.bitcarton.disso.core.utils.JedisUtil;
import com.bitcarton.disso.core.utils.SsoClientUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

/**
 * @author wwd 2021-06-28 10:12:21
 */
public class SsoClientFilter implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(SsoClientFilter.class);

    /**
     * 统一认证中心服务地址 Service address of unified certification authority
     */
    private String ssoServerUrl;

    /**
     * 将要重定向的路径 The path to be redirected
     */
    private String ssoClientUrl;

    /**
     * 退出登录地址 Exit login address
     */
    private String ssoLogoutPath;

    /**
     * 初始化过滤器 Initialize filter
     *
     */
    @Override
    public void init(FilterConfig filterConfig) {
        ssoServerUrl = filterConfig.getInitParameter(Config.SSO_SERVER_URL);
        ssoClientUrl = filterConfig.getInitParameter(Config.SSO_CLIENT_URL);
        ssoLogoutPath = filterConfig.getInitParameter(Config.SSO_LOGOUT_PATH);
        String ssoApplicationName = filterConfig.getInitParameter(Config.SSO_APPLICATION_NAME);
    }

    private final RequestMappingHandlerMapping handlerMapping;


    public SsoClientFilter(RequestMappingHandlerMapping handlerMapping) {
        this.handlerMapping = handlerMapping;
    }

    private Method getMethod(HttpServletRequest req) {
        HandlerExecutionChain handlerChain = null;
        try {
            handlerChain = handlerMapping.getHandler(req);
        } catch (Exception e) {
            logger.error(" get Method error ", e);
        }
        if (handlerChain == null) {
            return null;
        }
        HandlerMethod handler = (HandlerMethod) handlerChain.getHandler();
        return handler.getMethod();
    }


    /**
     * doFilter
     *
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        Method method = getMethod(req);
        if (null != method) {
            Login login = method.getAnnotation(Login.class);
            if (null != login) {
                if (login.handler() == Handler.PASS) {
                    chain.doFilter(req, resp);
                    return;
                }
            }
        }
        String servletPath = req.getServletPath();
        if (StringUtils.isNotBlank(ssoLogoutPath) && ssoLogoutPath.equals(servletPath)) {
            String logoutPageUrl = ssoServerUrl.concat(Config.SSO_LOGOUT);
            CookieUtil.remove(req, resp, Config.SSO_TOKEN);
            resp.sendRedirect(logoutPageUrl);
            return;
        }
        String token = CookieUtil.getValue(req, Config.SSO_TOKEN);
        String header = req.getHeader(Config.SSO_TOKEN);
        if (StringUtils.isNotBlank(header)){
            token=header;
        }
        if (StringUtils.isBlank(token)) {
            token = req.getParameter(Config.SSO_TOKEN);

            req.removeAttribute(Config.SSO_TOKEN);
        }
        if (StringUtils.isNotBlank(token)) {
            try {
                boolean isVerify = SsoLoginHelper.verifyToken(token);
                if (isVerify) {
                    //移除老的cookie
                    CookieUtil.remove(req, resp, Config.SSO_TOKEN);
                    CookieUtil.setCookie(resp, Config.SSO_TOKEN, token, Integer.MAX_VALUE, Config.COOKIE_PATH, true);
                    chain.doFilter(request, response);
                    return;
                } else {
                    //cookie验证不通过 为过期cookie清除掉
                    CookieUtil.remove(req, resp, Config.SSO_TOKEN);
                    SsoClientUtil.redirectToSsoLoginUrl(req, resp, ssoClientUrl, ssoServerUrl);
                }
            } catch (Exception e) {
                logger.error("verifyToken error", e);
            }
        } else {
            if (null!=method){
                ResponseBody methodAnnotation = method.getAnnotation(ResponseBody.class);
                if (null!=methodAnnotation){

                    SsoClientUtil.redirectToSsoLoginUrl(req, resp, ssoClientUrl, ssoServerUrl);
                    return ;
                }
                RestController annotation = method.getClass().getAnnotation(RestController.class);
                if (annotation!=null){
                    SsoClientUtil.redirectToSsoLoginUrl(req, resp, ssoClientUrl, ssoServerUrl);
                    return ;
                }
                SsoClientUtil.redirectToSsoUrl(req, resp, ssoClientUrl, ssoServerUrl,null);
                return ;
            }else{
                SsoClientUtil.redirectToSsoLoginUrl(req, resp, ssoClientUrl, ssoServerUrl);
            }

        }

    }

    /**
     * destroy
     */
    @Override
    public void destroy() {
        try {
            JedisUtil.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
